#include <algorithm/analytical_model/algorithm/cuda/GeometryUtils.cuh>
#include <algorithm/analytical_model/algorithm/cuda/VectorMath.cuh>
#include <algorithm/analytical_model/algorithm/cuda/receiver/ImagePlane.cuh>

using namespace solar::cuda;

ImagePlane::ImagePlane(cudaStream_t stream) : Receiver(stream) {}

void ImagePlane::init(float pixel_per_meter_for_receiver)
{
    pixel_length_ = 1.0F / float(pixel_per_meter_for_receiver);
    setResolution(pixel_per_meter_for_receiver);
    allocImage();
    // Calloc_image_xy();
    cleanImageContent();
}

// sum_of_x2, sum_of_y2, sum_of_xy, sum_of_weight
void ImagePlane::setResolution(float pixel_per_meter_for_receiver)
{
    resolution_.x = size_.x * float(pixel_per_meter_for_receiver);
    resolution_.y = size_.y * float(pixel_per_meter_for_receiver);
    n_resolution_ = resolution_.x * resolution_.y + resolution_.x + resolution_.y;
}

__device__ __host__ auto ImagePlane::intersect(const float3& orig, const float3& dir)
    -> std::tuple<float, float, float, bool>
{
    return rayParallelogramIntersect(orig, dir, rect_vertices_[0], rect_vertices_[1],
                                     rect_vertices_[3]);
}

void ImagePlane::setAxis(const float3& x, const float3& y)
{
    x_ = x;
    y_ = y;
    setVertex();
}

void ImagePlane::setVertex()
{
    rect_vertices_[0] = pos_ - 0.5 * size_.x * x_ - 0.5 * size_.y * y_;
    rect_vertices_[1] = pos_ - 0.5 * size_.x * x_ + 0.5 * size_.y * y_;
    rect_vertices_[2] = pos_ + 0.5 * size_.x * x_ + 0.5 * size_.y * y_;
    rect_vertices_[3] = pos_ + 0.5 * size_.x * x_ - 0.5 * size_.y * y_;
}

// heliostat focus on the pos of receiver
__host__ __device__ auto ImagePlane::getFocusCenter(const float3 & heliostat_position) -> float3
{
    return pos_;
}
